#include "G4RunManager.hh"
#include "G4UImanager.hh"
#include "G4VisExecutive.hh"
#include "G4UIExecutive.hh"
#include "LHEP.hh"
#include <QGSP_BERT.hh>
#include "KDMGlobals.hh"
#include "KDMPhysicsList.hh"
#include "KDMDetectorConstruction.hh"
#include "KDMPrimaryGeneratorAction.hh"
#include "KDMSteppingAction.hh"
#include <KDMTrackingAction.hh>
#include <KDMEventAction.hh>
#include "Randomize.hh"
#include <TFile.h>
#include <sstream>
#include <istream>
using namespace std;

void PrintUsage();

G4String eventInterfaceFilePath;
int neutronCount;
G4String positionFilePath;
int eventNum;
TH1D* photonEnergyDist;
ofstream tempOut;
stringstream tempSS;
bool CV;

int main(int argc, char** argv) {
	eventInterfaceFilePath = "";
	neutronCount = 0;
	positionFilePath = "";
	eventNum = -1;
	TFile* distFile = new TFile("distrib.root", "recreate");
	photonEnergyDist = new TH1D("photonED", "Photon Energy Distrib;energy;count", 10000, 0, 10000);
	tempOut.open("tempOut");
	bool startUI = false;

	for (int i = 1; i < argc; i++) {
		if (argv[i][0] == '-') {
			if (argv[i][1] == 'h') {
				PrintUsage();
				return 0;
			} else if (argv[i][1] == 'c') {
				i++;
				neutronCount = atoi(argv[i]);
			} else if (argv[i][1] == 'e') {
				i++;
				eventInterfaceFilePath = argv[i];
			} else if (argv[i][1] == 'p') {
				i++;
				positionFilePath = argv[i];
			} else if (argv[i][1] == 'u') {
				i++;
				startUI = true;
			} else {
				PrintUsage();
				return 0;
			}
		} else {
			PrintUsage();
			return 0;
		}
	}

	bool proceed = true;

	if (neutronCount == 0) {
		G4cout << "Must enter a neutron count > 0\n";
		proceed = false;
	}
	if (eventInterfaceFilePath == "") {
		G4cout << "Must provide event interface file path\n";
		proceed = false;
	}
	if (positionFilePath == "") {
		G4cout << "Must provide position file path\n";
		proceed = false;
	}

	if (!proceed) {
		PrintUsage();
		return 0;
	}

	G4long myseed = 336028;
	CLHEP::HepRandom::setTheSeed(myseed);

	// Make the run manager (runningMan)
	G4RunManager *runningMan = new G4RunManager();

	// Instantiate and initialize user initialization classes
	KDMDetectorConstruction *construction = new KDMDetectorConstruction();
	runningMan->SetUserInitialization(construction);

	G4VUserPhysicsList *physics = new QGSP_BERT();
	runningMan->SetUserInitialization(physics);

	// Instantiate and initialize visualization manager
	G4VisManager *visMan = new G4VisExecutive();
	visMan->SetVerboseLevel(1);
	visMan->Initialize();

	// Instantiate and initialize user action classes
	KDMPrimaryGeneratorAction *generator = new KDMPrimaryGeneratorAction(eventInterfaceFilePath, positionFilePath,
			neutronCount);
	runningMan->SetUserAction(generator);

	KDMEventAction* eventAction = new KDMEventAction();
	runningMan->SetUserAction(eventAction);

	KDMSteppingAction* stepAction = new KDMSteppingAction();
	runningMan->SetUserAction(stepAction);

	KDMTrackingAction* trackAction = new KDMTrackingAction();
	runningMan->SetUserAction(trackAction);

	// Initialize run manager
	runningMan->Initialize();

	// Get pointer to UI manager and UI executive, then start session
	G4UImanager *UIman = G4UImanager::GetUIpointer();
	UIman->ApplyCommand("/run/verbose 0");
	UIman->ApplyCommand("/event/verbose 0");
	UIman->ApplyCommand("/tracking/verbose 0");
	if (startUI) {
		UIman->ApplyCommand("/vis/scene/create");
		UIman->ApplyCommand("/vis/scene/add/trajectories");
		UIman->ApplyCommand("/vis/open OGLIX 1600x1000");
		UIman->ApplyCommand("/vis/viewer/zoomTo 9");
		sleep(20);
		for (int i = 0; i < 1; i++) {
			UIman->ApplyCommand("/run/beamOn");
		}
		int argcFake = 0;
		G4UIExecutive *ui = new G4UIExecutive(argcFake, argv);
		ui->SessionStart();
		delete ui;
	} else {
		std::stringstream ss;
		ss << "/run/beamOn " << neutronCount;
		UIman->ApplyCommand(ss.str());
	}

	delete visMan;
	delete runningMan;

	tempOut.close();
	photonEnergyDist->Write();
	distFile->Close();

	return 0;
}

void PrintUsage() {
	G4cout << "Usage:\n\t-c NeutronCount\n\t"
			<< "\n\t-e EventInterfaceFilePath\n\t-p PositionFilePath\n\t-u (start UI)\n";
}
